package com.franklin.ideaplugin.api.utils.psi;

import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiCodeBlock;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * @author Ye Junhui
 * @since 2024/3/7
 */
public class PsiMethodUtils {

    /**
     * 寻找抽象方法的实现方法
     * @param abstractMethod
     * @return
     */
    public static PsiMethod findAbstractMethodImpl(PsiMethod abstractMethod){
        //抽象类
        PsiClass abstractClass = abstractMethod.getContainingClass();
        if (Objects.isNull(abstractClass)){
            return null;
        }

        Project project = abstractMethod.getProject();
        PsiShortNamesCache psiShortNamesCache = PsiShortNamesCache.getInstance(project);
        GlobalSearchScope globalSearchScope = GlobalSearchScope.allScope(project);
        @NotNull PsiMethod[] psiMethods = psiShortNamesCache.getMethodsByName(abstractMethod.getName(), globalSearchScope);
        for (PsiMethod psiMethod : psiMethods) {
            //类
            PsiClass psiClass = psiMethod.getContainingClass();
            if (Objects.isNull(psiClass)){
                continue;
            }
            //相同类
            if (abstractClass.equals(psiClass)){
                continue;
            }
            //是否是实现类
            if (!PsiClassUtils.isInheritorOrEquals(abstractClass,psiClass)){
                continue;
            }
            //是否是抽象方法
            PsiCodeBlock psiCodeBlock = psiMethod.getBody();
            if (Objects.isNull(psiCodeBlock)){
                continue;
            }
            return psiMethod;
        }

        return null;
    }

    /**
     * 寻找方法返回值
     * @param psiMethod
     * @return
     */
    @NotNull
    public static List<PsiExpression> findMethodReturnExpression(@Nullable PsiMethod psiMethod){
        if (Objects.isNull(psiMethod)){
            return Collections.emptyList();
        }
        //方法代码块
        PsiCodeBlock psiCodeBlock = psiMethod.getBody();
        if (Objects.isNull(psiCodeBlock)){
            //接口方法，尝试寻找实现类
            PsiMethod abstractMethodImpl = findAbstractMethodImpl(psiMethod);
            if (Objects.isNull(abstractMethodImpl)){
                return Collections.emptyList();
            }
            psiCodeBlock = abstractMethodImpl.getBody();
        }

        //方法的返回表达式
        return PsiCodeBlockUtils.findCodeBlockReturnExpression(psiCodeBlock);
    }
}
